#pragma once

#include <QObject>
#include <QMenuBar>

#include <framework/mvp.h>

#include <models/model_mesh.h>

#include <widgets/mesh_widget.h>
#include <widgets/palette_widget.h>
#include <widgets/navigation_widget.h>

namespace presenters { namespace mesh_model {

  //
  // presenters::mesh_model::MeshModelWrapper
  //

  class Wrapper : public IMesh
  {
  public:
    Wrapper(models::Mesh *pRootModel_, const QString & FieldName_)
      : mpRootModel(pRootModel_), mpSubModel(pRootModel_), mFieldName(FieldName_)
    {
    }

    //
    // Interface
    //

    models::Mesh * GetRootModel()
    {
      return mpRootModel;
    }

    void SetSubModel(const QString & _Name)
    {
      models::Mesh * pSubModel = mpRootModel->findChild<models::Mesh *>(_Name);

      if (pSubModel == 0)
        pSubModel = mpRootModel;

      mpSubModel = pSubModel;
    }

    models::Mesh * GetSubModel()
    {
      return mpSubModel;
    }

// IMesh implementation

    // Vertex
    virtual const t_container_vertex &get_vertices() const
    {
      return mpSubModel->get_vertices();
    }
    
    virtual const t_container_color &get_vertices_colors() const
    {
      return mpSubModel->get_vertices_color(mFieldName);
    }
    
    // Elements
    virtual const t_container_element &get_elements(element_type type) const
    {
      return mpSubModel->get_nodes(type);
    }
    
    virtual const t_container_color   &get_elements_colors(element_type type) const
    {
      return mpSubModel->get_elements_color(type, mFieldName);
    }

  public:
    models::Mesh * mpRootModel;
    models::Mesh * mpSubModel;
    QString        mFieldName;
  };

  //
  // presenters::mesh_model::Mesh
  //

  class Mesh : public QObject
  {
    Q_OBJECT

  public:
    Mesh(models::Mesh *, widgets::Mesh *);
    ~Mesh();

  private slots:
    void on_update_model();
    void OnContextMenuRequested(const QPoint & _Pos);
    void OnFieldAction();
    void OnModelAction();
    void OnElementPicked(IMesh::element_type, int);
    void OnElementPickedDouble(IMesh::element_type, int);
    void OnSaveScreenshot();

  public:
    Wrapper      mWrapper;

  private:
    static void UpdateModelLevelMap(QMultiMap<int, QObject *> & ModelLevelMap, int Level, QObject * pModel);
    void AppendModelMenu(QMenu * pMenu, QObject * pModel);
  };

  //
  // presenters::mesh_model::Palette
  //

  class Palette : public QObject
  {
    Q_OBJECT

  public:
    Palette(models::Mesh *, widgets::Palette *);
    ~Palette();

  private slots:
    void on_update_model();
  };

  //
  // presenters::mesh_model::Navigation
  //

  class Navigation : public QObject
  {
    Q_OBJECT

  public:
    Navigation(QObject *parent = 0);
    Navigation(models::Mesh *, widgets::Navigation *);
    ~Navigation();

  private slots:
    void on_model_changed();
    void on_frame_changed();
  };
} } // namespace presenters { namespace mesh_model {
